package com.laivi.basic.module.orm;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.laivi.basic.annotation.orm.Table;
import com.laivi.basic.annotation.orm.Transient;
import com.laivi.basic.model.datastruct.ValueMap;
import com.laivi.basic.model.orm.ClassFilter;
import com.laivi.basic.model.orm.GenerateTable;
import com.laivi.basic.model.sql.BasicDB;
import com.laivi.basic.model.sql.Page;
import com.laivi.basic.module.log.Log;
import com.laivi.basic.module.log.Logs;
import com.laivi.basic.module.sql.DBDao;
import com.laivi.basic.module.sql.SqlDao;
import com.laivi.basic.util.DataUtil;
import com.laivi.basic.util.LangUtil;

/**
 * @author laivi.zhu@gmail.com
 * @date 2014-7-9
 * description:
 */
public abstract class ADao implements EntityDao {
	private static Log log=Logs.getLog(ADao.class);
	
	protected DBDao dbDao;
	
	protected GenerateTable generate;
	
	public ADao(BasicDB db){
		dbDao=new SqlDao(db);
		this.generate=new GenerateTable(db.getType());
	}
	
	public ADao(String url,String user,String password){
		dbDao=new SqlDao(url,user,password);
		this.generate=new GenerateTable(dbDao.getDBType());
	}
	
	@Override
	public <T> T orm(ValueMap value, Class<T> klass) {
		T obj=null;
		try {
			obj=klass.newInstance();
			for(Field field:LangUtil.getFields(klass)){
				try{
					field.setAccessible(true);
					field.set(obj, value.get(field.getName()));
				}catch(Exception e){
					log.error("set Field:"+field.getName()+" error!");
				}finally{
					field.setAccessible(false);
				}
			}
		} catch (InstantiationException e) {
			log.error(e);
		} catch (IllegalAccessException e) {
			log.error(e);
		}
		return obj;
	}
	
	public <T> List<T> orm(List<ValueMap> values,Class<T> klass){
		List<T> objs=new ArrayList<T>();
		try {
			for(Map<String,Object> value:values){
				T obj=klass.newInstance();
				for(Field field:LangUtil.getFields(klass)){
					boolean isAccess=false;
					try{
						isAccess=field.isAccessible();
						field.setAccessible(true);
						Transient tran=field.getAnnotation(Transient.class);
						if(tran==null && !DataUtil.isNull(value.get(field.getName()))){
							field.set(obj, value.get(field.getName()));
						}
					}catch(Exception e){
						log.error("set Field:"+field.getName()+" error!");
					}finally{
						field.setAccessible(isAccess);
					}
				}
				objs.add(obj);
			}
		} catch (InstantiationException e) {
			log.error("instantiation obj error:"+e.getMessage());
		} catch (IllegalAccessException e) {
			log.error("illegal access error:"+e.getMessage());
		}
		return objs;
	}
	
	public <T> Page<T> orm(Page<ValueMap> values,Class<T> klass){
		Page<T> page=new Page<T>();
		page.setRoot(this.orm(values.getRoot(), klass));
		page.setTotal(values.getTotal());
		page.setCurrentPage(values.getCurrentPage());
		page.setPageSize(values.getPageSize());
		page.setTotalPage(values.getTotalPage());
		return page;
	}
	
	public <T> ValueMap mor(T obj){
		ValueMap map=ValueMap.createMap();
		for(Field field:LangUtil.getFields(obj.getClass())){
			boolean isAccess=false;
			try {
				isAccess=field.isAccessible();
				field.setAccessible(true);
				Object value=field.get(obj);
				map.add(field.getName(), value);
			} catch (IllegalArgumentException e) {
				log.error(e);
			} catch (IllegalAccessException e) {
				log.error(e);
			}finally{
				field.setAccessible(isAccess);
			}
		}
		return map;
	}
	
	public <T> void create(Class<T> klass){
		this.dbDao.execute(generate.generateCreate(klass));
		String comments=generate.generateComments(klass);
		if(!DataUtil.isEmpty(comments)){
			this.dbDao.execute(comments);
		}
	}
	
	public void create(String packageName){
		for(Class<?> klass:LangUtil.scanPackage(packageName, new ClassFilter(){
			@Override
			public boolean accept(Class<?> klass) {
				return klass.isAnnotationPresent(Table.class);
			}})){
			if(!exist(klass)){
				create(klass);
			}
		}
	}
	
	public <T> boolean exist(Class<T> klass){
		Table table = klass.getAnnotation(Table.class);
		if(null!=table)
			return this.dbDao.isExist(table.value());
		return false;
	}
	
	public <T> void drop(Class<T> klass){
		Table table = klass.getAnnotation(Table.class);
		if(null!=table)
			this.dbDao.execute("drop table "+table.value());
	}
	
	public <T> void alert(Class<T> klass){
		
	}
	
	public <T> void truncate(Class<T> klass){
		Table table = klass.getAnnotation(Table.class);
		if(null!=table)
			this.dbDao.execute("truncate table "+table.value());
	}
}
